use std::{
    cmp,
    fs::{self, File},
    io::{self, BufWriter, Write},
    path::{Path, PathBuf},
    sync::{mpsc, Arc},
    thread,
};

use umya_spreadsheet::Worksheet;

use crate::excels::utils::ARR_STRING;

use super::{
    code_generater::CodeGenerater,
    datas::ColumnData,
    utils::{
        get_column_type, ARR_BYTE, ARR_FLOAT, ARR_INT, ARR_NUMBER, ARR_SHORT, ARR_UINT, ARR_U_BYTE,
        ARR_U_SHORT, BYTE, FLOAT, INT, NUMBER, SHORT, STRING, UINT, U_BYTE, U_SHORT,
    },
};

pub struct ExportInfo {
    pub input: String,
    pub output: String,
    pub script: String,
    pub type_idx: u32,
    pub title_idx: u32,
    pub comment_idx: u32,
    pub data_idx: u32,
}

impl ExportInfo {
    pub fn new(
        input: String,
        output: String,
        script: String,
        type_idx: u32,
        title_idx: u32,
        comment_idx: u32,
        data_idx: u32,
    ) -> ExportInfo {
        ExportInfo {
            input,
            output,
            script,
            title_idx,
            type_idx,
            comment_idx,
            data_idx,
        }
    }
}

pub fn export(info: Arc<ExportInfo>, code_generater: Arc<dyn CodeGenerater>) {
    let files = find_xlsx_files(Path::new(&info.input)).unwrap();

    let mut code_str = String::new();
    let mut enum_str = code_generater.generate_enum_head();

    println!("Start Export:");

    for file in files {
        export_file(&info, file, &code_generater, &mut code_str, &mut enum_str);
    }
    enum_str.push_str(&code_generater.generate_end());
    //写入代码定义文件
    let code_path = format!("{}/{}", &info.script, "ConfigTypeDefind.d.ts");
    write_txt_file(&code_path, &code_str);
    //写入枚举文件
    let enum_paht = format!("{}/{}", &info.script, "ConfigKeys.ts");
    write_txt_file(&enum_paht, &enum_str);
    println!("Export Complete!");
}

fn export_file(
    info: &Arc<ExportInfo>,
    file: PathBuf,
    generater: &Arc<dyn CodeGenerater>,
    code_str: &mut String,
    enum_str: &mut String,
) {
    let file_name = file
        .file_name()
        .unwrap()
        .to_str()
        .unwrap()
        .replace(".xlsx", "");

    let mut file_code_str = generater.generate_head(&file_name);

    let mut book = umya_spreadsheet::reader::xlsx::lazy_read(file.as_path()).unwrap();
    let sheets = book.get_sheet_collection_mut();
    for sheet in sheets {
        export_sheet(
            &file_name,
            sheet,
            generater,
            info,
            &mut file_code_str,
            enum_str,
        );
    }
    file_code_str.push_str(&generater.generate_end());
    code_str.push_str(&file_code_str);
}

fn export_sheet(
    file_name: &str,
    sheet: &Worksheet,
    code_generater: &Arc<dyn CodeGenerater>,
    info: &Arc<ExportInfo>,
    file_str: &mut String,
    enum_str: &mut String,
) {
    let mut max_row: usize = 0;
    let sheet_name = sheet.get_name();
    println!("  Sheet:{}\\{}=>{}", info.output, file_name, sheet_name);
    let mut sheet_vecs = Vec::new();
    // 总共要运行的线程数
    let total_threads = sheet.get_highest_column() as usize;
    if total_threads == 0 {
        return;
    }
    // 每批要运行的线程数
    let batch_size = 6;
    // //通讯频道
    let (tx, rx) = mpsc::channel();
    let mut handlers = Vec::new();
    let mut index = 0;
    for batch in (0..total_threads).step_by(batch_size) {
        let batch_end = cmp::min(batch + batch_size, total_threads);
        //创建当前批次线程
        for i in batch..batch_end {
            //通讯频道
            let thread_tx = tx.clone();
            //表单数据
            let sheet = sheet.clone();
            let file_name = file_name.to_string();
            let thread_export_info = Arc::clone(info);
            let handler = thread::spawn(move || {
                export_column(&file_name, sheet, i as u32, &thread_export_info, thread_tx);
            });
            handlers.push(handler);
        }
        for join_handle in handlers.drain(..(batch_end - batch)) {
            join_handle.join().unwrap();
        }
        while let Ok(msg) = rx.try_recv() {
            index += 1;
            //如果是有效列
            if msg.is_valid() {
                max_row = usize::max(max_row, msg.datas.len());
                sheet_vecs.push(msg);
            }
            //全部完成
            if index >= total_threads {
                // drop(tx);
                if max_row == 0 {
                    break;
                }
                //排序保证数据顺序
                sheet_vecs.sort_by(|a, b| a.title.cmp(&b.title));
                export_sheet_bin(file_name, sheet.get_name(), &sheet_vecs, info, max_row);
                file_str.push_str(&code_generater.generate(sheet_name, &sheet_vecs));
                enum_str.push_str(&code_generater.generate_enum(file_name, sheet_name));
                break;
            }
        }
    }
}

fn export_sheet_bin(
    file_name: &str,
    sheet_name: &str,
    datas: &Vec<ColumnData>,
    info: &Arc<ExportInfo>,
    max_row: usize,
) {
    let file = create_bin(&info.output, file_name, sheet_name);
    let mut writer = BufWriter::new(file);

    //列数
    let column = datas.len();
    let title_len_bytes = (column as u32).to_be_bytes();
    let _ = writer.write_all(&title_len_bytes);

    // 表头
    let titles = datas
        .iter()
        .map(|i| i.title.clone())
        .collect::<Vec<String>>();
    for i in titles {
        let title = i;
        let bytes = title.as_bytes();
        //u16长度
        let _ = writer.write_all(&(bytes.len() as u16).to_be_bytes());
        let _ = writer.write_all(bytes);
    }
    //类型
    let types = datas
        .iter()
        .map(|i: &ColumnData| i.true_type)
        .collect::<Vec<u8>>();
    let _ = writer.write_all(&types);

    //数据行数
    let row = max_row;

    let data_col_byte = (row as u32).to_be_bytes();
    let _ = writer.write_all(&data_col_byte);

    for row_idx in 0..row {
        for column_idx in 0..datas.len() {
            if let Some(data) = datas.get(column_idx) {
                let cell_type = data.true_type;
                let mut cell_value = String::new();
                if let Some(cell_str) = data.datas.get(row_idx) {
                    cell_value.push_str(cell_str);
                } else {
                    cell_value = String::new();
                }
                // println!("{}-{}:{} {}", row_idx, column_idx, cell_value, cell_type);
                // //数组类型
                if cell_type > 9 {
                    write_array(&cell_type, cell_value, &mut writer);
                } else {
                    write_value(&cell_type, cell_value, &mut writer);
                }
            }
        }
    }
    let _ = writer.flush();
}

fn export_column(
    file_name: &str,
    sheet: Worksheet,
    index: u32,
    info: &Arc<ExportInfo>,
    sender: mpsc::Sender<ColumnData>,
) {
    let mut column_data = ColumnData::new();
    let column_idx = index + 1;
    // 表头
    if let Some(data_cell) = sheet.get_cell((column_idx, info.title_idx)) {
        column_data.title = data_cell.get_value().to_string();
    }
    //类型
    if let Some(data_cell) = sheet.get_cell((column_idx, info.type_idx)) {
        column_data.low_type = data_cell.get_value().to_string().to_lowercase();
    }
    //注释
    if let Some(data_cell) = sheet.get_cell((column_idx, info.comment_idx)) {
        column_data.comment = data_cell.get_value().to_string();
    }
    //行数
    let row = sheet.get_highest_row();
    for i in info.data_idx..row + 1 {
        //数据
        if let Some(cell) = sheet.get_cell((column_idx, i + 1)) {
            column_data.datas.push(cell.get_value().to_string());
        }else{
            column_data.datas.push(String::new());
        }
    }
    column_data.true_type = get_column_type(file_name, &column_data);
    sender.send(column_data).unwrap();
}

fn write_array(true_type: &u8, value: String, writer: &mut BufWriter<File>) {
    let type_u8 = *true_type;
    let arr: Vec<&str> = value.split("|").collect();
    let count_byte = (arr.len() as u32).to_be_bytes();
    let _ = writer.write_all(&count_byte);
    for i in arr {
        match type_u8 {
            ARR_BYTE | ARR_U_BYTE | ARR_U_SHORT | ARR_INT | ARR_UINT | ARR_FLOAT | ARR_NUMBER => {
                write_number(true_type, i.to_string(), writer)
            }
            ARR_STRING => {
                let bytes = i.as_bytes();
                let _ = writer.write_all(&(bytes.len() as u16).to_be_bytes());
                let _ = writer.write_all(bytes);
            }
            _ => {
                panic!("不支持的数组类型{}", type_u8);
            }
        }
    }
}

fn write_value(true_type: &u8, value: String, writer: &mut BufWriter<File>) {
    match *true_type {
        BYTE | U_BYTE | SHORT | U_SHORT | INT | UINT | FLOAT | NUMBER => {
            write_number(true_type, value, writer)
        }
        STRING => {
            let bytes = value.as_bytes();
            let _ = writer.write_all(&(bytes.len() as u16).to_be_bytes());
            let _ = writer.write_all(bytes);
        }
        _ => {
            panic!("不支持的类型{}", true_type);
        }
    }
}

fn write_number(true_type: &u8, value: String, writer: &mut BufWriter<File>) {
    match *true_type {
        BYTE | ARR_BYTE => {
            let num: i8 = value.parse().unwrap_or(0);
            let _ = writer.write_all(&num.to_be_bytes());
        }
        U_BYTE | ARR_U_BYTE => {
            let num: u8 = value.parse().unwrap_or(0);
            let _ = writer.write_all(&num.to_be_bytes());
        }
        SHORT | ARR_SHORT => {
            let num: i16 = value.parse().unwrap_or(0);
            let _ = writer.write_all(&num.to_be_bytes());
        }
        U_SHORT | ARR_U_SHORT => {
            let num: u16 = value.parse().unwrap_or(0);
            let _ = writer.write_all(&num.to_be_bytes());
        }
        INT | ARR_INT => {
            let num: i32 = value.parse().unwrap_or(0);
            let _ = writer.write_all(&num.to_be_bytes());
        }
        UINT | ARR_UINT => {
            let num: u32 = value.parse().unwrap_or(0);
            let _ = writer.write_all(&num.to_be_bytes());
        }
        FLOAT | ARR_FLOAT => {
            let num: f32 = value.parse().unwrap_or(0.0);
            let _ = writer.write_all(&num.to_be_bytes());
        }
        NUMBER | ARR_NUMBER => {
            let num: f64 = value.parse().unwrap_or(0.0);
            let _ = writer.write_all(&num.to_be_bytes());
        }
        _ => {
            panic!("不支持的数字类型{}", true_type);
        }
    }
}

fn find_xlsx_files(dir: &Path) -> io::Result<Vec<PathBuf>> {
    let mut files = Vec::new();
    // 读取目录中的所有条目
    if let Ok(entries) = fs::read_dir(dir) {
        for entry in entries {
            if let Ok(entry) = entry {
                let path = entry.path();
                if path.is_dir() {
                    // 如果是目录，则递归查找
                    let sub_xlsx_files = find_xlsx_files(&path)?;
                    files.extend(sub_xlsx_files);
                } else if let Some(ext) = path.extension() {
                    if ext == "xlsx" {
                        let file_name = path
                            .file_name()
                            .unwrap()
                            .to_str()
                            .unwrap()
                            .replace(".xlsx", "");
                        //忽略临时文件
                        if !file_name.contains("~$") {
                            files.push(path);
                        }
                    }
                }
            } else {
                // 返回错误，而不是打印
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    "Failed to read directory entry",
                ));
            }
        }
    } else {
        // 返回读取目录时的错误
        return Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to read directory",
        ));
    }
    Ok(files)
}

/**
 * 写txt文件
 */
fn write_txt_file(path: &str, data: &str) {
    let path = Path::new(path);
    if check_file_exists(path) {
        fs::remove_file(path).expect("删除文件失败");
    }
    let mut file = File::create(path).expect("创建文件失败");
    file.write_all(data.as_bytes()).expect("写入文件失败");
}

fn create_bin(output: &str, file_name: &str, sheet_name: &str) -> File {
    let dir_str = format!("{}/{}", output, file_name);
    let dir_path = Path::new(&dir_str);
    if !check_file_exists(dir_path) {
        fs::create_dir(dir_path).expect("创建目录失败");
    }
    let file_path_str = format!("{}/{}/{}.bin", output, file_name, sheet_name);
    let file_path = Path::new(&file_path_str);
    //存在则删除老的
    if check_file_exists(file_path) {
        fs::remove_file(file_path).expect("删除文件失败");
    }
    let result: File = File::create(file_path).expect("创建文件失败");
    result
}

fn check_file_exists(dir_path: &Path) -> bool {
    match fs::metadata(dir_path) {
        Ok(_) => true, // 如果能够获取元数据，说明目录存在
        Err(err) => {
            if err.kind() == io::ErrorKind::NotFound {
                false // 如果错误是NotFound，说明目录不存在
            } else {
                // 处理其他可能的错误情况，例如权限不足
                panic!("Error checking : {:?}", err);
            }
        }
    }
}
